<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <title>Arc Diagram</title>
    <style>
      .g6-tooltip {
        border: 1px solid #e2e2e2;
        border-radius: 4px;
        font-size: 12px;
        color: #545454;
        background-color: rgba(255, 255, 255, 0.9);
        padding: 10px 8px;
        box-shadow: rgb(174, 174, 174) 0px 0px 10px;
      }
    </style>
  </head>
  
  <body>
    <div id="mountNode"></div>
    <script src="../build/g6.js"></script>
    <script src="./assets/jquery-3.2.1.min.js"></script>
    <script>
      const colors = [ 'rgb(64, 174, 247)', 'rgb(108, 207, 169)', 'rgb(157, 223, 125)',
      'rgb(240, 198, 74)', 'rgb(221, 158, 97)', 'rgb(141, 163, 112)', 'rgb(115, 136, 220)',
      'rgb(133, 88, 219)', 'rgb(203, 135, 226)', 'rgb(227, 137, 163)' ];
      const graph = new G6.Graph({
        container: 'mountNode',
        width: 1000,
        height: 800,
        linkCenter: true,
        modes: {
          default: [{
            type: 'edge-tooltip',
            formatText(model) {
              const text = 'source: ' + model.sourceName
                + '<br/> target: ' + model.targetName;
              return text;
            },
            shouldUpdate: e => {
              return true;
            }
          }]
        },
        defaultNode: {
          size: [10, 10],
          color: 'steelblue',
          style: {
            opacity: 0.8,
            lineWidth: 1,
            stroke: '#999'
          }
        },
        defaultEdge: {
          size: 1,
          color: '#e2e2e2',
          style: {
            opacity: 0.6,
            lineAppendWidth: 3
          }
        },
        edgeStateStyles: {
          hover: {
            opacity: 1,
            lineWidth: 2
          }
        }
      });
      graph.on('edge:mouseenter', e => {
        const edge = e.item;
        graph.setItemState(edge, 'hover', true);
      });
      graph.on('edge:mouseleave', e => {
        const edge = e.item;
        graph.setItemState(edge, 'hover', false);
      });

      $.getJSON('./assets/data/relationship-with-weight.json', data => {
        const edges = data.edges;
        const nodes = data.nodes;
        const nodeMap = new Map();
        const clusterMap = new Map();
        let clusterId = 0;
        const n = nodes.length;
        const begin = [50, 500];
        const end = [850, 500];
        const xLength = end[0] - begin[0];
        const yLength = end[1] - begin[1];
        const xSep = xLength / n;
        const ySep = yLength / n;
        nodes.forEach((node, i) => {
          node.x = begin[0] + i * xSep;
          node.y = begin[1] + i * ySep;
          nodeMap.set(node.id, node);
          // cluster
          if (node.cluster && clusterMap.get(node.cluster) === undefined) {
            clusterMap.set(node.cluster, clusterId);
            clusterId ++;
          }
          const id = clusterMap.get(node.cluster);
          if (node.style) {
            node.style.fill = colors[id % colors.length];
          } else {
            node.style = {
              fill: colors[id % colors.length]
            }
          }
          // label
          node.label = node.name;
          node.labelCfg = {
            position: 'center',
            style: {
              rotate: 90,
              textAlign: 'start'
            }
          }
        });
        edges.forEach((edge, i) => {
          edge.shape = 'arc';
          const source = nodeMap.get(edge.source);
          const target = nodeMap.get(edge.target);
          const endsSepStep = (target.x - source.x) / xSep;
          const sign = endsSepStep < 0 ? -1 : 1;
          const curveOffset = sign * 10 * Math.ceil(Math.abs(endsSepStep));
          edge.curveOffset = curveOffset;
          edge.color = source.style.fill;
          edge.sourceName = source.name;
          edge.targetName = target.name;
        });

        // map the value to node size
        let maxValue = -9999,
        minValue = 9999;
        nodes.forEach(n => {
          if (maxValue < n.value) maxValue = n.value;
          if (minValue > n.value) minValue = n.value;
        });
        const sizeRange = [3, 30];
        const sizeDataRange = [minValue, maxValue];
        scaleNodeProp(nodes, 'size', 'value', sizeDataRange, sizeRange);

        graph.data(data);
        graph.render();
      });

      function scaleNodeProp(nodes, propName, refPropName, dataRange, outRange) {
        const outLength = outRange[1] - outRange[0];
        const dataLength = dataRange[1] - dataRange[0];
        nodes.forEach(n => {
          n[propName] = (n[refPropName] - dataRange[0]) * outLength / dataLength + outRange[0];
        });
      }
    </script>
  </body>

</html>